/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package co.edu.udistrital.servlet;

import co.edu.udistrital.util.XSSUtils;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author timotheos
 */
public class XSSFilter implements Filter {

    private static final Log log = LogFactory.getLog(XSSFilter.class);
    private static final boolean DEBUG_ENABLED = false;
    // The filter configuration object we are associated with.  If
    // this value is null, this filter instance is not currently
    // configured. 
    private FilterConfig filterConfig = null;

    public XSSFilter() {
    }

    private void doBeforeProcessing(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
        if (DEBUG_ENABLED) {
            log.debug("XSSFilter:DoBeforeProcessing");
        }
    }

    private void doAfterProcessing(ServletRequest request, ServletResponse response)
            throws IOException, ServletException {
        if (DEBUG_ENABLED) {
            log.debug("XSSFilter:DoAfterProcessing");
        }
    }

    /**
     *
     * @param request The servlet request we are processing
     * @param response The servlet response we are creating
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {

        if (DEBUG_ENABLED) {
            log.debug("XSSFilter:doFilter()");
        }

        request =
                new HttpServletRequestWrapper((HttpServletRequest) request) {

                    /**
                     * Caching map
                     */
                    private Map<String, String> singleParamsMap = null;
                    /**
                     * Caching map
                     */
                    private Map parameterMap = null;
                    /**
                     * Caching map
                     */
                    private Map<String, String[]> paramValuesMap = null;

                    /**
                     * Caching map
                     */
                    private Map<String, String> headersMap = null;

                    @Override
                    public String getParameter(String name) {
                        String parameter = null;

                        if (this.singleParamsMap == null || (parameter = this.singleParamsMap.get(name)) == null) {
                            this.singleParamsMap = this.singleParamsMap == null ? new HashMap<String, String>(super.getParameterMap().size()) : this.singleParamsMap;
                            singleParamsMap.put(name, parameter = XSSUtils.clean(super.getParameter(name)));
                        }

                        return parameter;
                    }

                    @Override
                    public Map getParameterMap() {
                        if (this.parameterMap == null) {
                            this.parameterMap = XSSUtils.clean(super.getParameterMap());
                        }

                        return this.parameterMap;
                    }

                    @Override
                    public String[] getParameterValues(String name) {
                        String[] parameterValues = null;

                        if (this.paramValuesMap == null || (parameterValues = this.paramValuesMap.get(name)) == null) {
                            this.paramValuesMap = this.paramValuesMap == null ? new HashMap<String, String[]>(super.getParameterMap().size()) : this.paramValuesMap;
                            this.paramValuesMap.put(name, parameterValues = XSSUtils.clean(super.getParameterValues(name)));
                        }

                        return parameterValues;
                    }

                    @Override
                    public String getHeader(String name) {
                        String value = null;

                        if (headersMap == null || (value = this.headersMap.get(name)) == null) {
                            this.headersMap = this.headersMap == null ? new HashMap<String, String>(40) : this.headersMap;
                            this.headersMap.put(name, value = XSSUtils.clean(super.getHeader(name)));
                        }

                        return value;
                    }
                };

        doBeforeProcessing(request, response);

        chain.doFilter(request, response);

        doAfterProcessing(request, response);
    }

    /**
     * Return the filter configuration object for this filter.
     */
    public FilterConfig getFilterConfig() {
        return (this.filterConfig);
    }

    /**
     * Set the filter configuration object for this filter.
     *
     * @param filterConfig The filter configuration object
     */
    public void setFilterConfig(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }

    /**
     * Destroy method for this filter 
     */
    public void destroy() {
    }

    /**
     * Init method for this filter 
     */
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
        if (filterConfig != null) {
            if (DEBUG_ENABLED) {
                log.debug("XSSFilter:Initializing filter");
            }
        }
    }

    /**
     * Return a String representation of this object.
     */
    @Override
    public String toString() {
        if (filterConfig == null) {
            return ("XSSFilter()");
        }
        StringBuffer sb = new StringBuffer("XSSFilter(");
        sb.append(filterConfig);
        sb.append(")");
        return (sb.toString());
    }
}
